로딩 중이에요... 🐣
01 이상치 탐지 | ✅ 저자: 이유정(박사)
이상치(Outlier)란? 다른 데이터들과 너무 동떨어진 값을 말해요. 예:
- 평균 나이가 20~70살인데 200살이 있다면? → 이상치!
- 월급이 대부분 200만~500만인데 1억 원이 있다면? → 이상치!
이런 값이 있으면 분석 결과나 머신러닝 예측이 엉뚱하게 나올 수 있어요.
이런 이상치가 왜 생기는가?
입력 실수
나이: 28살 입력하려다 280살 입력
측정 오류
체중 센서가 고장 나서 -15kg 표시
진짜 특이한 사례
일반 직원 연봉은 3천만 원인데, CEO 연봉 5억
단위 착오
월급 500인데 만원 → 원을 잘못 처리해서 5,000,000
왜 이상치가 문제일까?
- 평균 계산을 왜곡시켜요.
- 머신러닝 모델이 이상치에 끌려가서 엉뚱하게 학습해요.
- 시각화할 때 데이터 범위가 너무 커져 트렌드가 안 보일 수도 있어요.
이상치를 찾는 대표적인 방법 2가지
- IQR 방법 (사분위수 기반) 박스 플롯(Boxplot)에 쓰이는 방식이에요.
핵심 개념:
Q1
: 1사분위수 (25% 지점 값)
Q3
: 3사분위수 (75% 지점 값)
IQR
: Q3 - Q1, 중간 50% 범위
이상치 기준:
Q1 - 1.5×IQR 보다 작거나,
Q3 + 1.5×IQR 보다 큰 값
df = pd.read_csv("csv_files/combined_customers.csv")
# Q1, Q3 계산
Q1 = df['age'].quantile(0.25)
Q3 = df['age'].quantile(0.75)
IQR = Q3 - Q1
# 이상치 조건
outliers = df[(df['age'] < Q1 - 1.5 * IQR) | (df['age'] > Q3 + 1.5 * IQR)]
# 나이가 (1사분위수보다 1.5 * IQR만큼 작거나) 또는
# 나이가 (3사분위수보다 1.5 * IQR만큼 큰)
# → 그런 사람은 이상치로 간주한다
# 박스 플롯 시각화
import seaborn as sns
import matplotlib.pyplot as plt
sns.boxplot(x=df['age'])
plt.show()
박스 플롯에서 동그란 점으로 표시되는 것들이 이상치입니다.
Q1 - 1.5 * IQR
: 너무 작은 값 (이 범위 아래는 이상치)Q3 + 1.5 * IQR
: 너무 큰 값 (이 범위 위는 이상치)
Q1 = df['age'].quantile(0.25)
나이(age) 데이터를 작은 값부터 큰 값까지 정렬했을 때, 아래쪽 25% 지점의 값을 구합니다. 이걸 제1사분위수 (Q1) 라고 합니다. 예: 나이 순서대로 줄 세웠을 때, 하위 25% 지점의 나이
Q3 = df['age'].quantile(0.75)
나이 데이터에서 위쪽 75% 지점의 값, 즉 제3사분위수 (Q3) 를 구해요.
예: 나이 순서대로 줄 세웠을 때, 상위 25%가 시작되는 나이
IQR = Q3 - Q1
IQR (Interquartile Range) 는
Q1과 Q3 사이의 값의 범위(=중간 50%) 를 의미해요.
즉, 대부분 사람들이 있는 '정상적인 범위' 라고 보면 돼요.
- Z-score 방법 (평균 기반) 평균(Mean) 과 표준편차(Standard Deviation) 를 기준으로 판단하는 방법
핵심 개념:
- Z-score는 "이 값이 평균에서 얼마나 떨어졌는지" 를 나타내는 지표예요.
- 보통 Z-score가 +3 이상 또는 -3 이하이면 "너무 멀리 있다" → 이상치로 간주
예시:
- 평균 나이가 40이고, 표준편차가 10이라면
→ 나이 70은 (70 - 40) / 10 = Z-score 3.0 → 이상치!
→ 나이 10도 Z-score -3.0 → 이상치! 표준편차 구하기:
# 나이데이터
ages = [20, 22, 24, 26, 28]
# 평균값은
(20+22+24+26+28)/5 = 24
# 각 값에서 평균을 뺀 차이 구하기 (편차)
[20-24, 22-24, 24-24, 26-24, 28-24] → [-4, -2, 0, 2, 4]
# 편차 제곱
[(-4)^2, (-2)^2, 0^2, 2^2, 4^2] → [16, 4, 0, 4, 16]
# 제곱값 평균
(16+4+0+4+16)/5 = 5
# 제곱값 평균의 루트 = 표준편차
√8 = 2.83
즉 이 데이터의 표준 편차는 약 2.83입니다.
pandas공식으로 표준편차 구하기:
import pandas as pd
ages = [20, 22, 24, 26, 28]
df = pd.DataFrame({'age': ages})
std_population = df['age'].std(ddof=0)
print("표준편차:", std_population)
Z-Score 기반 이상치 탐지 (정규분포 가정 / 평균과 표준편차 기준)
import numpy as np
# 평균과 표준편차
mean_age = np.mean(df['age'])
std_age = np.std(df['age'])
# Z-score 계산
df['z_score'] = (df['age'] - mean_age) / std_age
# Z-score가 ±3을 넘으면 이상치
outliers = df[np.abs(df['z_score']) > 3]
- Z-score는 각 값이 평균에서 얼마나 떨어져 있는지 측정
- Z-score가 +3 또는 -3을 넘는 데이터는 이상치로 간주
- 데이터가 정규분포일 때 효과적
- 사용 예: 센서 데이터, 시험 점수 등
IQR 기반 이상치 탐지 (중간값 기반 / 사분위수 이용, 비정규 분포에 강함)
import pandas as pd
df = pd.read_csv("csv_files/combined_customers.csv")
# Q1, Q3 계산
Q1 = df['age'].quantile(0.25)
Q3 = df['age'].quantile(0.75)
IQR = Q3 - Q1
print(Q1)
print(Q3)
print(IQR)
# 이상치 탐지
outliers = df[(df['age'] < (Q1 - 1.5 * IQR)) | (df['age'] > (Q3 + 1.5 * IQR))]
print(outliers)
import seaborn as sns
import matplotlib.pyplot as plt
# 박스 플롯을 사용한 이상치 시각화
sns.boxplot(x=df['age'])
plt.show()
- IQR은 Q3 - Q1: 중간 50% 구간
Q1 - 1.5*IQR
,Q3 + 1.5*IQR
을 벗어난 값 → 이상치- 극단값에 덜 민감, 비정규분포 데이터에도 안정적
- 사용 예: 가격, 소득, 나이 분포 등